package com.pai4j.log.dao;

import com.pai4j.log.entity.OperationLogEntity;
import com.pai4j.log.vo.LogStatisticsVO;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.Date;
import java.util.List;

/**
 * 操作日志数据访问接口
 *
 * @author: CYM-pai
 * @date: 2025/07/29 15:35
 **/
@Repository
public interface IOperationLogDAO extends JpaRepository<OperationLogEntity, String>, JpaSpecificationExecutor<OperationLogEntity> {

    /**
     * 根据链路追踪ID查询日志
     *
     * @param traceId 链路追踪ID
     * @return 日志列表
     */
    List<OperationLogEntity> findByTraceIdOrderByCreateTimeAsc(String traceId);

    /**
     * 根据用户ID和时间范围查询日志
     *
     * @param userId    用户ID
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @param pageable  分页参数
     * @return 分页日志数据
     */
    Page<OperationLogEntity> findByUserIdAndCreateTimeBetweenOrderByCreateTimeDesc(
            String userId, Date startTime, Date endTime, Pageable pageable);

    /**
     * 根据模块和时间范围查询日志
     *
     * @param module    模块名称
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @param pageable  分页参数
     * @return 分页日志数据
     */
    Page<OperationLogEntity> findByModuleAndCreateTimeBetweenOrderByCreateTimeDesc(
            String module, Date startTime, Date endTime, Pageable pageable);

    /**
     * 统计模块操作数量
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 统计结果
     */
    @Query("SELECT new com.pai4j.log.vo.LogStatisticsVO('module', l.module, COUNT(l), " +
           "SUM(CASE WHEN l.status = 1 THEN 1 ELSE 0 END), " +
           "SUM(CASE WHEN l.status = 0 THEN 1 ELSE 0 END), " +
           "CAST(SUM(CASE WHEN l.status = 1 THEN 1 ELSE 0 END) * 100.0 / COUNT(l) AS double), " +
           "AVG(l.costTime), MAX(l.costTime), MIN(l.costTime)) " +
           "FROM OperationLogEntity l " +
           "WHERE l.createTime BETWEEN :startTime AND :endTime " +
           "GROUP BY l.module " +
           "ORDER BY COUNT(l) DESC")
    List<LogStatisticsVO> getModuleStatistics(@Param("startTime") Date startTime, @Param("endTime") Date endTime);

    /**
     * 统计操作类型数量
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 统计结果
     */
    @Query("SELECT new com.pai4j.log.vo.LogStatisticsVO('operation', l.operation, COUNT(l), " +
           "SUM(CASE WHEN l.status = 1 THEN 1 ELSE 0 END), " +
           "SUM(CASE WHEN l.status = 0 THEN 1 ELSE 0 END), " +
           "CAST(SUM(CASE WHEN l.status = 1 THEN 1 ELSE 0 END) * 100.0 / COUNT(l) AS double), " +
           "AVG(l.costTime), MAX(l.costTime), MIN(l.costTime)) " +
           "FROM OperationLogEntity l " +
           "WHERE l.createTime BETWEEN :startTime AND :endTime " +
           "GROUP BY l.operation " +
           "ORDER BY COUNT(l) DESC")
    List<LogStatisticsVO> getOperationStatistics(@Param("startTime") Date startTime, @Param("endTime") Date endTime);

    /**
     * 统计用户操作数量
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 统计结果
     */
    @Query("SELECT new com.pai4j.log.vo.LogStatisticsVO('user', l.userId, COUNT(l), " +
           "SUM(CASE WHEN l.status = 1 THEN 1 ELSE 0 END), " +
           "SUM(CASE WHEN l.status = 0 THEN 1 ELSE 0 END), " +
           "CAST(SUM(CASE WHEN l.status = 1 THEN 1 ELSE 0 END) * 100.0 / COUNT(l) AS double), " +
           "AVG(l.costTime), MAX(l.costTime), MIN(l.costTime)) " +
           "FROM OperationLogEntity l " +
           "WHERE l.createTime BETWEEN :startTime AND :endTime " +
           "GROUP BY l.userId " +
           "ORDER BY COUNT(l) DESC")
    List<LogStatisticsVO> getUserStatistics(@Param("startTime") Date startTime, @Param("endTime") Date endTime);

    /**
     * 删除指定时间之前的日志
     *
     * @param beforeTime 时间点
     * @return 删除数量
     */
    Long deleteByCreateTimeBefore(Date beforeTime);
}
